import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.table.DefaultTableModel;
import java.io.*;
import java.util.Vector;

/**
 * @author Huhao
 * &#064;date  2024/11/12
 */

public class LL1 extends JFrame implements ActionListener{
    private static final long serialVersionUID = 1L;
    private JFrame frame;

    JButton b0;
    JPanel p1,p2,p3,p4,p5,p6;
    JTextArea t1,t2,t3;
    JButton b1,b2,b3,b4,b5,b6;
    JLabel l0,l1,l3,l4;
    JTable table;
    Box vbox;

    DefaultTableModel dtm;
    String Vn[]=null;
    Vector<String> P=null;

    int firstComplete[]=null;//存储已判断过first的数据
    char first[][]=null;//存储最后first结果
    int followComplete[]=null;//存储已判断过follow的数据
    char follow[][]=null;//存储最后follow结果
    char select[][]=null;//存储最后select结果
    int LL=0;//标记是否为LL（1）
    String vt_tou[]=null;//储存Vt
    Object shuju[][]=null;//存储表达式数据
    char toNull[]=null;//存储能否推出空

    LL1()//基本布局
    {
        frame = new JFrame();
        frame.setTitle("LL（1）分析");
        frame.setLocation(500,200);
        frame.setSize(800,750);

        b0=new JButton("读入文法(S为开始)");
        b4=new JButton("保存文法1");
        b6=new JButton("保存文法2");
        b3=new JButton("清空");
        b5=new JButton("形式转换");

        b1=new JButton("产生预测分析表");

        l0=new JLabel("输入字符串：");
        t2=new JTextArea(1,30);
        b2=new JButton("判断");

        l1=new JLabel("输入的文法为：");
        l3=new JLabel("                                                                         分析的结果为：                                    ");
        l4=new JLabel("预测分析表为：");


        vbox = Box.createVerticalBox();

        p1=new JPanel();
        p2=new JPanel();
        p3=new JPanel();
        p4=new JPanel();
        p5=new JPanel();
        p6=new JPanel();

        t1=new JTextArea(24,20);
        t3=new JTextArea(24,40);


        table=new JTable();;
        JScrollPane jp1=new JScrollPane(t1);
        JScrollPane jp2=new JScrollPane(t2);
        JScrollPane jp3=new JScrollPane(t3);

        vbox.add(p4);
        vbox.add(p5);
        vbox.add(p6);
        p4.add(b0);
        p4.add(b5);
        p4.add(b3);
        p4.add(b1);
        p4.add(b4);
        p4.add(b6);

        p5.add(l0);
        p5.add(jp2);
        p5.add(b2);


        p6.add(l1);
        p6.add(l3);
        p1.add(vbox);
        p2.add(jp1);
        p2.add(jp3);

        p3.add(l4);
        p3.add(new JScrollPane(table));
        frame.add(p1,"North");
        frame.add(p2,"Center");
        frame.add(p3,"South");

        b0.addActionListener(this);
        b1.addActionListener(this);
        b2.addActionListener(this);
        b3.addActionListener(this);
        b4.addActionListener(this);
        b6.addActionListener(this);
        b5.addActionListener(this);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        table.setPreferredScrollableViewportSize(new Dimension(660,200));

    }

    public void actionPerformed(ActionEvent e)
    {
        if(e.getSource()==b0)//读文件
        {
            File getPath;
            JFileChooser jf=new JFileChooser("./");
            FileNameExtensionFilter filter = new FileNameExtensionFilter("文本文档(*.txt)", "txt");
            jf.setFileFilter(filter);
            int value=jf.showOpenDialog(frame);
            if(value==JFileChooser.APPROVE_OPTION){
                getPath=jf.getSelectedFile();
                File fp=getPath;
                File fileflag=fp;
                BufferedReader reader = null;
                String tempString = null;
                String sum="";
                int line =1;
                try {
                    reader = new BufferedReader(new FileReader(fp));
                    while ((tempString = reader.readLine()) != null) {
                        if(sum.equals(""))
                            sum=sum+tempString;
                        else
                            sum=sum+"\n"+tempString;
                        line ++ ;
                    }
                    this.t1.setText(sum);
                    reader.close();
                } catch (FileNotFoundException e1) {

                } catch (IOException e2) {

                }finally{
                    if(reader != null){
                        try {
                            reader.close();
                        } catch (IOException e3) {

                        }
                    }
                }
            }else{
            }
        }
        if(e.getSource()==b4)//保存文件1
        {
            FileDialog savedia;
            File fileflag=null;
            savedia=new FileDialog(frame,"保存",FileDialog.SAVE);
            if(fileflag==null){
                savedia.setVisible(true);
                String dirPath=savedia.getDirectory();
                String fileName=savedia.getFile();
                fileName=fileName+".txt";
                if(dirPath==null||fileName==null)
                    return ;
                fileflag=new File(dirPath,fileName);
                try{
                    BufferedWriter bfwt=new BufferedWriter(new FileWriter(fileflag));
                    String t= t1.getText();
                    bfwt.write(t);
                    bfwt.close();
                }
                catch (IOException ex){
                    throw new RuntimeException();
                }
            }
        }
        if(e.getSource()==b6)//保存文件2
        {
            FileDialog savedia;
            File fileflag=null;
            savedia=new FileDialog(frame,"保存",FileDialog.SAVE);
            if(fileflag==null){
                savedia.setVisible(true);
                String dirPath=savedia.getDirectory();
                String fileName=savedia.getFile();
                fileName=fileName+".txt";
                if(dirPath==null||fileName==null)
                    return ;
                fileflag=new File(dirPath,fileName);
                try{
                    BufferedWriter bfwt=new BufferedWriter(new FileWriter(fileflag));
                    String t= t3.getText();
                    bfwt.write(t);
                    bfwt.close();
                }
                catch (IOException ex){
                    throw new RuntimeException();
                }
            }
        }
        if(e.getSource()==b5)//形式转换
        {
            String s_ori[]=t1.getText().split("\n");
            String s[]=new String[100];
            t1.setText("");

            int temp=0;
            int flag=0;
            for(int i=0;i< s_ori.length;i++){

                String left = s_ori[i].split("->")[0];//左部
                if(left.equals("S")){
                    flag=1;
                }

                String right = s_ori[i].split("->")[1];//右部
                String rights[] = right.split("\\|");
                for(int j=0;j<rights.length;j++){
                    s[temp]=left+"→"+rights[j];
                    temp++;

                }


            }
            char start = s[0].charAt(0);
            for(int i=0;s[i]!=null;i++){
                s[i]=s[i].replace("$","#");
                if(flag==0){
                    s[i]=s[i].replace(start,'S');
                    //第一行的左部的字符默认为文法的开始符

                }

                if(i==0){
                    t1.append(s[i]);
                }
                else{
                    t1.append("\n");
                    t1.append(s[i]);
                }
            }

        }
        if(e.getSource()==b1)//产生follow，first，select
        {
            t3.setText("");
            int Vnnum=0,k;
            Vn=new String[100];
            P=new Vector<String>();
            String s[]=t1.getText().split("\n");
            //判断长度是否符合
            for(int i=0;i<s.length;i++)
            {
                if(s.length<2){
                    t3.setText("文法输入有误，请重新输入");
                    return;
                }
                if(s[i].charAt(0)<='Z'&&s[i].charAt(0)>='A'&&s[i].charAt(1)=='→')
                {
                    for(k=0;k<Vnnum;k++)
                    {
                        if(Vn[k].equals(s[i].substring(0, 1))){
                            break;
                        }
                    }
                    if(Vnnum==0||k>=Vnnum)
                    {
                        //存入Vn数据
                        Vn[Vnnum]=s[i].substring(0, 1);
                        Vnnum++;
                    }
                    P.add(s[i]);
                }
                else
                {
                    t3.setText("文法输入有误，请重新输入");
                    return;
                }
            }
            toNull=new char[100];
            first=new char[Vnnum][100];
            int flag=0;
            String firstVn[]=null;
            firstComplete=new int[Vnnum];
            //求First集
            for(int i=0;Vn[i]!=null;i++)
            {
                flag=0;
                firstVn=new String[20];
                if((flag=add_First(first[i],Vn[i],firstVn,flag))==-1)return;
                firstComplete[i]=1;

            }
            t3.append("first集："+"\n");//显示
            for(int i=0;Vn[i]!=null;i++)
            {
                t3.append("first("+Vn[i]+")={ ");
                for(int j=0;first[i][j]!='\0';j++)//
                {
                    if(j==0)
                        t3.append(first[i][j]+"");
                    else
                        t3.append(" , "+first[i][j]);
                }
                t3.append("}"+"\n");
            }
            follow=new char[Vnnum][100];
            String followVn[]=null;
            followComplete=new int[Vnnum];

            //求Follow集
            for(int i=0;Vn[i]!=null;i++)//
            {
                flag=0;
                followVn=new String[20];
                if((flag=tianjiaFollow(follow[i],Vn[i],followVn,flag))==-1)return;
                followComplete[i]=1;
            }
            t3.append("follow集："+"\n");//显示
            for(int i=0;Vn[i]!=null;i++)
            {
                t3.append("follow("+Vn[i]+")={ ");
                for(int j=0;follow[i][j]!='\0';j++)
                {
                    if(j==0)
                        t3.append(follow[i][j]+"");
                    else
                        t3.append(" , "+follow[i][j]);
                }
                t3.append("}"+"\n");
            }
            select=new char[P.size()][100];

            //求Select集
            for(int i=0;i<P.size();i++)//
            {
                flag=0;
                tianjiaSelect(select[i],(String)P.elementAt(i),flag);
            }
            t3.append("select集："+"\n");//显示
            for(int i=0;i<P.size();i++)
            {
                t3.append("select("+(String)P.elementAt(i)+")={ ");
                for(int j=0;select[i][j]!='\0';j++)
                {
                    if(j==0)
                        t3.append(select[i][j]+"");
                    else
                        t3.append(" , "+select[i][j]);
                }
                t3.append("}"+"\n");
            }

            //判断Select交集是否为空？
            for(int i=0;Vn[i]!=null;i++)
            {
                int biaozhi=0;
                char save[]=new char[100];
                for(int j=0;j<P.size();j++)
                {
                    String t=(String)P.elementAt(j);

                    if(t.substring(0,1).equals(Vn[i]))
                    {
                        for(k=0;select[j][k]!='\0';k++)
                        {
                            if(panduanChar(save,select[j][k]))
                            {
                                save[biaozhi]=select[j][k];
                                biaozhi++;
                            }
                            else
                            {
                                t3.append("不是LL（1）文法！！"+"\n");
                                return;
                            }
                        }
                    }
                }
            }

            char Vt[]=new char[100];
            int biaozhi=0;
            for(int i=0;i<P.size();i++)
            {
                String t=(String)P.elementAt(i);

                for(int j=2;j<t.length();j++)
                {
                    if(t.charAt(j)>'Z'||t.charAt(j)<'A')
                    {
                        if(panduanChar(Vt,t.charAt(j)))
                        {
                            //把表达式右侧的终结符存入Vt
                            Vt[biaozhi]=t.charAt(j);
                            biaozhi++;
                        }
                    }
                }
            }
            //若推出空集，直接加入“#”
            if(panduanChar(Vt,'#'))
            {
                Vt[biaozhi]='#';
                biaozhi++;
            }

            //生成预测分析表
            vt_tou=new String[biaozhi+1];
            shuju=new String[Vnnum][biaozhi+1];
            String f="";
            vt_tou[0]=f;
            for(int i=0;i<biaozhi;i++)
            {
                vt_tou[i+1]=String.valueOf(Vt[i]);
            }
            for(int i=0;i<Vnnum;i++)
            {
                shuju[i][0]=Vn[i];
            }
            for(int i=0;i<P.size();i++)//
            {
                String t=(String)P.elementAt(i);
                int j;
                for(j=0;j<Vn.length;j++)
                {
                    if(Vn[j].equals(t.substring(0,1)))//
                    {
                        break;
                    }
                }
                for(k=0;select[i][k]!='\0';k++)
                {
                    int y=panduanXulie(Vt,select[i][k]);
                    shuju[j][y+1]=t.substring(1);
                }
            }
            //显示预测分析表
            dtm=new DefaultTableModel(shuju,vt_tou);
            table.setModel(dtm);
            LL=1;
        }
        if(e.getSource()==b3)//清空列表
        {

            t1.setText("");
            t2.setText("");
            t3.setText("");
            Vn=null;
            P=null;
            firstComplete=null;
            first=null;
            followComplete=null;
            follow=null;
            select=null;
            dtm=new DefaultTableModel();
            table.setModel(dtm);

        }
        if(e.getSource()==b2)//输入字符串并预测分析
        {
            t3.setText("");
            if(LL==1)
            {
                String s=t2.getText();
                for(int i=0;i<s.length();i++)
                {
                    if(s.charAt(i)=='\0')
                    {
                        t3.setText("字符串中请不要加入空格"+"\n");
                        return;
                    }
                }
                char zifu[]=new char[100];//剩余输入串
                char fenxi[]=new char[100];//分析栈
                zifu[0]='#';
                fenxi[1]='S';
                fenxi[0]='#';
                int fzifu=1;
                int ffenxi=2;
                for(int i=s.length()-1;i>=0;i--)
                {
                    zifu[fzifu]=s.charAt(i);
                    fzifu++;
                }
                int buzhou=2;
                char n[]=new char[65];//存储要显示的内容

                t3.append("步骤                分析栈                   剩余输入串           所用产生式或匹配"+"\n");
                n[0]='1';
                n[2]='\t';
                n[14]='S';
                n[15]='#';
                n[16]='\t';
                int u=29;
                for(int i=fzifu-1;i>=0;i--)
                {
                    n[u]=zifu[i];
                    u++;
                }
                n[u+1]='\t';
                while(!(fenxi[ffenxi-1]=='#'&&zifu[fzifu-1]=='#'))//剩余输入串不为#则分析
                {
                    int i,j;
                    char t=zifu[fzifu-1];
                    char k=fenxi[ffenxi-1];

                    if(t==k)//产生式匹配
                    {
                        n[49]=k;
                        n[50]='匹';
                        n[51]='配';

                        t3.append(String.copyValueOf(n)+"\n");

                        n=new char[65];
                        fzifu--;
                        ffenxi--;
                        if(buzhou<10)
                            n[0]=(char)('0'+buzhou);//显示步骤数
                        else
                        {
                            n[0]=(char)('0'+buzhou/10);
                            n[1]=(char)('0'+buzhou%10);
                        }
                        n[2]='\t';
                        u=14;
                        for(int y=ffenxi-1;y>=0;y--)//处理分析栈，出栈
                        {
                            n[u]=fenxi[y];
                            u++;
                        }
                        n[u+1]='\t';
                        u=29;

                        for(int y=fzifu-1;y>=0;y--)//处理剩余字符串，消除一个字符
                        {
                            n[u]=zifu[y];
                            u++;
                        }
                        n[u+1]='\t';
                        buzhou++;
                        continue;
                    }

                    for(i=0;Vn[i]!=null;i++)
                    //搜寻所用产生式的左部
                    {
                        if(Vn[i].equals(String.valueOf(k)))break;
                    }
                    for(j=0;j<vt_tou.length;j++)
                    //判断是否匹配
                    {
                        if(vt_tou[j].equals(String.valueOf(t)))break;
                    }
                    if(j>=vt_tou.length)
                    //全部产生式都不能符合则报错
                    {
                        t3.append(String.copyValueOf(n));

                        t3.append("\n"+"该串不是该文法的句型"+"\n");
                        return;
                    }

                    Object result1=shuju[i][j];
                    if(result1==null)
                    {
                        t3.append(String.copyValueOf(n));

                        t3.append("\n"+"该串不是该文法的句型"+"\n");
                        return;
                    }
                    else
                    //找到所用产生式
                    {
                        n[49]=Vn[i].charAt(0);
                        u=50;
                        String result=(String)result1;
                        for(int y=0;y<result.length();y++)
                        {
                            n[u]=result.charAt(y);
                            u++;
                        }
                        n[u+1]='\t';
                        t3.append(String.copyValueOf(n)+"\n");

                        n=new char[65];

                        ffenxi--;
                        for(i=result.length()-1;i>0;i--)
                        //将分析栈内非终结符换为右边表达式
                        {
                            if(result.charAt(i)!='#')


                            {
                                fenxi[ffenxi]=result.charAt(i);
                                ffenxi++;
                            }
                        }
                    }
                    if(buzhou<10)//按步骤显示

                        n[0]=(char)('0'+buzhou);
                    else
                    {
                        n[0]=(char)('0'+buzhou/10);
                        n[1]=(char)('0'+buzhou%10);
                    }
                    n[2]='\t';
                    u=14;

                    for(int y=ffenxi-1;y>=0;y--)
                    {
                        n[u]=fenxi[y];
                        u++;
                    }
                    n[u+1]='\t';
                    u=29;
                    for(int y=fzifu-1;y>=0;y--)
                    {
                        n[u]=zifu[y];
                        u++;
                    }
                    n[u+1]='\t';
                    buzhou++;
                }

                t3.append("\n"+"该串是此文法的句型"+"\n");
                return;
            }
            else
            {
                t3.setText("请依次输入LL（1）文法，进行文法判断"+"\n");
                return;
            }

        }
    }

    private int add_First(char a[],String b,String firstVn[],int flag)
    {
        if(panduanString(firstVn,b.charAt(0)))
        {
            addString(firstVn,b);
        }
        else
        {
            return flag;
        }
        for(int i=0;i<P.size();i++)
        {

            String t=(String)P.elementAt(i);
            for(int k=2;k<t.length();k++)
            {
                if(t.substring(0, 1).equals(b))
                {
                    if(t.charAt(k)>'Z'||t.charAt(k)<'A')
                    //表达式右端第i个不是非终结符
                    {
                        if(flag==0||panduanChar(a,t.charAt(k)))
                        {

                            if(t.charAt(k)=='#')
                            //#时直接加入first
                            {
                                if(k+1==t.length())
                                {
                                    a[flag]=t.charAt(k);
                                    flag++;
                                }
                                int flag1=0;
                                for(int j=0;toNull[j]!='\0';j++)
                                //所求非终结符进入yn_null**
                                {
                                    if(toNull[j]==b.charAt(0))
                                    //判断能否推出空
                                    {
                                        flag1=1;break;
                                    }
                                }
                                if(flag1==0)
                                {
                                    int j;
                                    for(j=0;toNull[j]!='\0';j++)
                                    {

                                    }
                                    toNull[j]=b.charAt(0);
                                }
                                continue;
                            }
                            else
                            //终结符直接加入first**
                            {
                                a[flag]=t.charAt(k);
                                flag++;
                                break;
                            }
                        }break;
                    }
                    else
                    //非终结符
                    {
                        if(!panduanString(Vn,t.charAt(k)))
                        {
                            int p=firstComplete(t.charAt(k));
                            //当该非终结符的first已经求出
                            if(p!=-1)
                            {
                                flag=addElementFirst(a,p,flag);
                                //直接加入所求first
                            }
                            else if((flag=add_First(a,String.valueOf(t.charAt(k)),firstVn,flag))==-1)
                                return -1;
                            int flag1=0;
                            for(int j=0;toNull[j]!='\0';j++)
                            //当非终结符的first有空
                            {
                                if(toNull[j]==t.charAt(k))
                                {
                                    flag1=1;break;
                                }
                            }
                            if(flag1==1)
                            //当非终结符的first能推出空
                            {
                                if(k+1==t.length()&&panduanChar(a,'#'))
                                //之后无符号，且所求first无#
                                {
                                    a[flag]='#';//first中加入#
                                    flag++;
                                }
                                continue;//判断下一个字符
                            }
                            else
                            {
                                break;
                            }
                        }
                        else
                        {
                            t3.setText("文法输入有误"+"\n");
                            return -1;
                        }
                    }
                }
            }
        }
        return flag;
    }

    //用递归法计算Follow
    private int tianjiaFollow(char a[],String b,String followVn[],int flag)
    {
        if(panduanString(followVn,b.charAt(0))){addString(followVn,b);}
        else
        {
            return flag;
        }
        if(b.equals("S"))
        //当为S时#存入follow
        {
            a[flag]='#';
            flag++;
        }
        for(int i=0;i<P.size();i++)
        {
            String t=(String)P.elementAt(i);
            for(int j=2;j<t.length();j++)
            {
                if(t.charAt(j)==b.charAt(0)&&j+1<t.length())
                {
                    if(t.charAt(j+1)!='\0')
                    {
                        if((t.charAt(j+1)>'Z'||t.charAt(j+1)<'A'))
                        //所求为终结符
                        {
                            if(flag==0||panduanChar(a,t.charAt(2)))
                            //自身
                            {
                                a[flag]=t.charAt(j+1);
                                flag++;
                            }
                        }

                        else
                        //所求为非终结符
                        {
                            int k;
                            for(k=0;Vn[k]!=null;k++)
                            {
                                if(Vn[k].equals(String.valueOf(t.charAt(j+1))))
                                {
                                    break;
                                    //找寻下一个非终结符的Vn位置
                                }

                            }
                            flag=addElementFirst(a,k,flag);
                            //把下一个非终结符first加入所求follow集
                            for(k=j+1;k<t.length();k++)
                            {
                                if((t.charAt(j+1)>'Z'||t.charAt(j+1)<'A'))break;
                                else
                                {
                                    if(panduan_kong(t.charAt(k)))
                                    {}
                                    else
                                    {
                                        break;
                                    }
                                }
                            }
                            if(k>=t.length())
                            //下一个非终结符可推出空，把表达式左边非终结符的follow集加入所求follow集
                            {
                                int p=followComplete(t.charAt(0));
                                if(p!=-1)
                                {
                                    flag=addElementFollow(a,p,flag);
                                }
                                else if((flag=tianjiaFollow(a,String.valueOf(t.charAt(0)),followVn,flag))==-1)
                                    return -1;
                            }
                        }
                    }
                    else
                    {
                        t3.setText("文法输入有误,请重新输入"+"\n");
                        return -1;
                    }

                }
                if(t.charAt(j)==b.charAt(0)&&j+1==t.length())
                //下一个字符为空，把表达式左边非终结符的follow集加入所求follow集
                {
                    int p=followComplete(t.charAt(0));
                    if(p!=-1)
                    {
                        flag=addElementFollow(a,p,flag);
                    }
                    else if((flag=tianjiaFollow(a,String.valueOf(t.charAt(0)),followVn,flag))==-1)
                        return -1;
                }
            }
        }
        return flag;
    }

    //计算Select
    private void tianjiaSelect(char a[],String b,int flag)
    {
        int i=2;
        int biaozhi=0;
        while(i<b.length())
        {
            if((b.charAt(i)>'Z'||b.charAt(i)<'A')&&b.charAt(i)!='#')//是终结符
            {
                a[flag]=b.charAt(i);//将这个字符加入到Select**，结束Select**的计算
                break;
            }
            else if(b.charAt(i)=='#')
            {
                int j;
                for(j=0;Vn[i]!=null;j++)
                //将表达式左侧的非终结符的follow加入select
                {
                    if(Vn[j].equals(b.substring(0,1)))
                    {
                        break;
                    }
                }
                for(int k=0;follow[j][k]!='\0';k++)
                {
                    if(panduanChar(a,follow[j][k]))
                    {
                        a[flag]=follow[j][k];
                        flag++;
                    }
                }
                break;
            }
            else if(b.charAt(i)>='A'&&b.charAt(i)<='Z'&&i+1<b.length())
            //是非终结符且有下一个字符
            {
                int j;
                for(j=0;Vn[i]!=null;j++)
                {
                    if(Vn[j].equals(String.valueOf(b.charAt(i))))
                    {
                        break;
                    }
                }
                for(int k=0;first[j][k]!='\0';k++)
                {
                    if(panduanChar(a,first[j][k]))
                    //把表达式右侧所有非终结符的first集加入。
                    {
                        if(first[j][k]=='#')
                        //first中存在空
                        {
                            biaozhi=1;
                        }
                        else
                        {
                            a[flag]=first[j][k];
                            flag++;
                        }
                    }
                }
                if(biaozhi==1)
                //把右侧所有非终结符的first中的#去除
                {
                    i++;biaozhi=0;continue;
                }
                else
                {
                    biaozhi=0;break;
                }
            }
            else if(b.charAt(i)>='A'&&b.charAt(i)<='Z'&&i+1>=b.length())
            //是非终结符且没有下一个字符
            {
                int j;
                for(j=0;Vn[i]!=null;j++)
                {
                    if(Vn[j].equals(String.valueOf(b.charAt(i))))
                    {
                        break;
                    }
                }
                for(int k=0;first[j][k]!='\0';k++)
                {
                    if(panduanChar(a,first[j][k]))
                    {
                        if(first[j][k]=='#')
                        {
                            biaozhi=1;
                            //表达式右侧能推出空，标记
                        }
                        else
                        {
                            a[flag]=first[j][k];
                            //不能推出空，直接将first集加入select集
                            flag++;
                        }

                    }
                }
                if(biaozhi==1)
                //表达式右侧能推出空
                {
                    for(j=0;Vn[i]!=null;j++)
                    {
                        if(Vn[j].equals(b.substring(0,1)))
                        {
                            break;
                        }
                    }
                    for(int k=0;follow[j][k]!='\0';k++)
                    {
                        if(panduanChar(a,follow[j][k]))
                        {
                            a[flag]=follow[j][k];
                            //将将表达式左侧的非终结符的follow加入select
                            flag++;
                        }
                    }
                    break;
                }
                else
                {
                    biaozhi=0;break;
                }
            }
        }
    }

    //返回b在Vt[]的位置
    private int panduanXulie(char Vt[],char b)
    {
        int i;
        for(i=0;Vt[i]!='\0';i++)
        {
            if(Vt[i]==b)break;
        }
        return i;
    }
    //判断b是否在a中，在返回false，不在返回true
    private boolean panduanChar(char a[],char b)
    {

        for(int i=0;a[i]!='\0';i++)
        {
            if(a[i]==b)return false;

        }
        return true;
    }
    //判断b是否在a中，在返回false，不在返回true
    private boolean panduanString(String a[],char b)
    {
        for(int i=0;a[i]!=null;i++)
        {
            if(a[i].equals(String.valueOf(b)))return false;

        }
        return true;
    }
    //把b加入字符串组firstVn[]
    private void addString(String firstVn[],String b)
    {
        int i;
        for(i=0;firstVn[i]!=null;i++)
        {
        }
        firstVn[i]=b;
    }
    //判断b是否已完成first判断
    private int firstComplete(char b)
    {
        int i;
        for(i=0;Vn[i]!=null;i++)
        {
            if(Vn[i].equals(String.valueOf(b)))
            {
                if(firstComplete[i]==1)return i;
                else return -1;
            }

        }
        return -1;
    }
    //判断b是否已完成follow判断
    private int followComplete(char b)
    {
        for(int i=0;Vn[i]!=null;i++)
        {
            if(Vn[i].equals(String.valueOf(b)))
            {
                if(followComplete[i]==1)return i;
                else return -1;
            }

        }
        return -1;
    }
    //把相应终结符添加到first**中
    private int addElementFirst(char a[],int p,int flag)
    {
        for(int i=0;first[p][i]!='\0';i++)
        {
            if(panduanChar(a,first[p][i])&&first[p][i]!='#')
            {
                a[flag]=first[p][i];
                flag++;
            }
        }
        return flag;
    }
    //把相应终结符添加到follow**中
    private int addElementFollow(char a[],int p,int flag)
    {
        for(int i=0;follow[p][i]!='\0';i++)
        {
            if(panduanChar(a,follow[p][i]))
            {
                a[flag]=follow[p][i];
                flag++;
            }
        }
        return flag;
    }
    //判断a能是否包含空
    private boolean panduan_kong(char a)
    {
        int i;
        for(i=0;Vn[i]!=null;i++)
        {
            if(Vn[i].equals(String.valueOf(a)))
            {
                break;
            }

        }
        for(int j=0;first[i][j]!='\0';j++)
        {
            if(first[i][j]=='#')return true;
        }

        return false;
    }

}
